为什么要使用 redis-cluster


1. 并发问题

  • redis官方生成可以达到 10万/每秒,每秒执行10万条命令 

  • 假如业务需要每秒100万的命令执行呢?

2. 数据量太大

  • 一台服务器内存正常是16~256G,假如你的业务需要500G内存,

  • 新浪微博作为世界上最大的redis存储,就超过1TB的数据,去哪买这么大的内存条?各大公司有自己的解决方案,推出各自的集群功能,核心思想都是将数据分片(sharding)存储在多个redis实例中,每一片就是一个redis实例。

  • 各大企业集群方案:

    • twemproxy由Twitter开源

    • Codis由豌豆荚开发,基于GO和C开发

    • redis-cluster官方3.0版本后的集群方案

3. 解决方案

  • 配置一个超级牛逼的计算机,超大内存,超强cpu,但是问题是价格。。。


  • 正确的应该是考虑分布式,加机器,把数据分到不同的位置,分摊集中式的压力,一堆机器做一件事


数据分布


1. 客户端分片

  • redis3.0集群采用P2P模式,完全去中心化,将redis所有的key分成了16384个槽位,每个redis实例负责一部分slot,集群中的所有信息通过节点数据交换而更新

  • redis实例集群主要思想是将redis数据的key进行散列,通过hash函数特定的key会映射到指定的redis节点上

2. 数据分布原理图


2. 数据分布的理论

  • 分布式数据库首要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个子集

  • 常见的分区

    • 顺序分区
    • 哈希分区
    • 一致性哈希分区
    • 虚拟槽分区(redis-cluster采用的方式)

顺序分区



哈希分区



  • 例如按照节点取余的方式,分三个节点

  • 1~100的数据对3取余,可以分为三类:

    • 余数为0
    • 余数为1
    • 余数为2

  • 那么同样的分4个节点就是hash(key)%4

  • 节点取余的优点是简单,客户端分片直接是哈希+取余

一致性哈希


  • 客户端进行分片,哈希+顺时针取余

虚拟槽分区


1. 虚拟槽分区的介绍

  • redis-cluster 采用的是虚拟槽分区

  • 虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有的数据映射到一个固定范围内的整数集合,整数定义为槽(slot)

  • Redis Cluster槽的范围是0 ~ 16383

  • 槽是集群内数据管理和迁移的基本单位。采用大范围的槽的主要目的是为了方便数据的拆分和集群的扩展

  • 每个节点负责一定数量的槽

2. 虚拟槽分区的示意图


搭建 redis-cluster


1. 搭建 redis-cluster 的步骤

  1. 准备多个redis(准备几匹马)
  2. redis 分配主从(几匹马分配主从)
  3. 分配槽位给 redis(分配槽位给马)

2. redis-cluster 的什么

  • 将所有的数据(keys *)分配给6个redis,6个redis的身份信息 -> 例如有 6 个reids

    • 3个主
    • 3个从

  • redis-cluster 使用哈希槽算法,将数据分为 0~16383 个槽位

  • 将所有的数据(keys *)分配到这些槽位当中

2. redis-cluster 集群架构

  • 多个服务端,负责读写,彼此通信,redis指定了16384个槽。

  • 多个redis,负责数据传输,redis分配16384个槽位,管理数据。

  • ruby的脚本自动就把分配槽位这事做了


环境的准备


1. 环境的准备 -> 创建 6 个redis

  • 注意: 无需手动设置主从关系,当开启了 redis-cluster 集群后,它会自动进行设置

  • redis支持多实例的功能,我们在单机演示集群搭建,需要6个实例,三个是主节点,三个是从节点,数量为6个节点才能保证高可用的集群

    • 注意: 只需要创建 6 个redis,不用设置主从关系!!!,不用设置主从关系!!!,不用设置主从关系!!!

  • 注意: 这里只演示创建一个redis,其余的redis配置只是端口的不一样而已

  • 创建 redis-cluster 文件夹

    • 创建文件夹 /opt/redis-4.0.10/my_redis_cluster -> 用于存放 redis-cluster 配置 和 redis 配置文件,方便管理

mkdir /opt/redis-4.0.10/my_redis_cluster

  • 创建 redis 配置文件

touch /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf

  • 修改 redis 配置文件

    • 进入配置文件

vim /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf

    • 修改配置文件

# 绑定远程连接ip,如需要远程访问当前服务器的redis(即: 让别人连接你的redis),那么就需要填写当前服务器的ip -> 0.0.0.0 代表 127.0.0.1 也代表 当前服务器ip
bind 0.0.0.0

# redis 端口
port 7001

# 是否后台运行 redis,在执行 redis-server redis.conf 命令时,如果为 yes 那么就不进入阻塞状态(即: 还可以输入其他命令),如果为 no 进入阻塞状态 (即: 无法输入别的命令)
daemonize yes

# 日志文件,注意: /data/7001/ 目录必须存在(即: 如果没有就需要手动创建)
logfile "/data/7001/redis.log"

# 配置 redis 的数据存放文件夹,一般存放redis的持久化存储文件和redis的日志文件等,注意: /data/7001/ 目录必须存在(即: 如果没有就需要手动创建)
dir /data/7001

# 定义 RDB 持久化文件名
dbfilename dump-7001.rdb

# 开启集群模式
cluster-enabled yes

# 集群内部的配置文件
cluster-config-file nodes-7001.conf

# redis cluster需要16384个slot都正常的时候才能对外提供服务,换句话说,只要任何一个slot异常那么整个cluster不对外提供服务。 因此生产环境一般为no
cluster-require-full-coverage no

  • 创建并修改其余5个redis配置文件

sed 's/7001/7002/g' /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf > /opt/redis-4.0.10/my_redis_cluster/redis-7002.conf

sed 's/7001/7003/g' /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf > /opt/redis-4.0.10/my_redis_cluster/redis-7003.conf

sed 's/7001/7004/g' /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf > /opt/redis-4.0.10/my_redis_cluster/redis-7004.conf

sed 's/7001/7005/g' /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf > /opt/redis-4.0.10/my_redis_cluster/redis-7005.conf

sed 's/7001/7006/g' /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf > /opt/redis-4.0.10/my_redis_cluster/redis-7006.conf

  • 创建reids配置文件所需要的文件夹

mkdir /data/{7001,7002,7003,7004,7005,7006}

  • 查看创建后的6个redis配置文件

ls /opt/redis-4.0.10/my_redis_cluster/


2. 启动和检查 6 个 redis

  • 启动 6 个 redis

redis-server /opt/redis-4.0.10/my_redis_cluster/redis-7001.conf

redis-server /opt/redis-4.0.10/my_redis_cluster/redis-7002.conf

redis-server /opt/redis-4.0.10/my_redis_cluster/redis-7003.conf

redis-server /opt/redis-4.0.10/my_redis_cluster/redis-7004.conf

redis-server /opt/redis-4.0.10/my_redis_cluster/redis-7005.conf

redis-server /opt/redis-4.0.10/my_redis_cluster/redis-7006.conf

  • 查看 6 个 redis 是否启动

ps -ef | grep redis


  • 此时 redis-cluster 集群还不可使用,可以通过登录redis进行查看

[root@kevin_linux ~ 16:01:44]# redis-cli -p 7001
127.0.0.1:7001> set addr hengli
(error) CLUSTERDOWN Hash slot not served

创建开启 redis-cluster


1. 准备 ruby 环境

  • 因为 redis-cluster 是基于 ruby 环境开发的

  • 下载 ruby 包到 /opt 目录下

cd /opt

wget https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz

  • 解压 ruby 包到 /opt 目录下

tar -zxvf ruby-2.3.1.tar.gz

  • 为开始编译做准备

    • 进入 ruby-2.3.1 文件夹中

cd /opt/ruby-2.3.1

    • 为开始编译做准备 -> 指定 ruby 的安装路径

./configure --prefix=/opt/ruby/

  • 编译且安装 ruby

    • 进入 ruby-2.3.1 文件夹中

cd /opt/ruby-2.3.1

    • 编译且安装 ruby

make && make install

  • 配置环境变量

cp /opt/ruby/bin/ruby /usr/local/bin/

cp /opt/ruby/bin/gem /usr/local/bin/

2. 安装 ruby 可以操作 redis 的模块

  • ruby 的 redis 模块的作用是在 ruby 环境可以操作 redis

  • 将 ruby 的 redis 模块下载到 /opt 目录下

cd /opt

wget http://rubygems.org/downloads/redis-3.3.0.gem

  • 安装 ruby 的 redis 模块

gem install -l /opt/redis-3.3.0.gem

  • 查看是否安装了 ruby 的 redis 模块

gem list -- check redis gem

  • 安装 redis-trib.rb 命令(即: 添加环境变量)

    • 查看 redis-trib.rb 可执行命令在哪

[root@kevin_linux ~ 17:00:04]# find /opt -name redis-trib.rb
/opt/redis-4.0.10/src/redis-trib.rb

    • 安装 redis-trib.rb 命令(即: 添加环境变量)

cp /opt/redis-4.0.10/src/redis-trib.rb /usr/local/bin/

3. 一键开启 redis-cluster 集群

  • 这一步的操作就是 分配槽位、分配主从关系

  • redis-cluster 集群会自动分配主从关系 7001、7002、7003 为主redis 7004、7005、7006 为从 redis

# 1 表示每个 主redis 有一个 从redis

redis-trib.rb create --replicas 1 10.0.0.3:7001 10.0.0.3:7002 10.0.0.3:7003 10.0.0.3:7004 10.0.0.3:7005 10.0.0.3:7006


4. 查看 redis 的主从身份关系

redis-cli -p 7001 info replication

redis-cli -p 7002 info replication

redis-cli -p 7003 info replication

redis-cli -p 7004 info replication

redis-cli -p 7005 info replication

redis-cli -p 7006 info replication

查看 redis-cluster 集群状态


  • 查看某个redis的集群状态

redis-cli -p 7001 cluster info

  • 查看所有redis的集群状态 -> 使用哪个reids端口都没有关系,只要是集群里的redis端口

redis-cli -p 7001 cluster nodes

  • 查看主redis的集群状态 -> 使用哪个reids端口都没有关系,只要是集群里的redis端口

redis-cli -p 7001 cluster nodes | grep master

  • 查看从redis的集群状态 -> 使用哪个reids端口都没有关系,只要是集群里的redis端口

redis-cli -p 7001 cluster nodes | grep slave

redis-cluster 的使用


注意: 如果使用了 redis-cluster 那么在日常使用中就要连接 redis-cluster 的端口,不要连接 redis 的端口(就算连接了,也无法写入数据)

1. 进入 redis 集群

  • -c : 表示开启集群功能 -> 如果不带该参数,那么进入到redis后无法正常操作redis

  • 注意: 使用哪个端口的主redis都没有关系,只要是集群里的redis端口,因为 redis-cluster 会自动切换的

redis-cli -c -p 7001

2. 写入一条数据

[root@kevin_linux ~ 20:04:26]# redis-cli -c -p 7001
127.0.0.1:7001> set addr hengli
-> Redirected to slot [12790] located at 10.0.0.3:7003 # 当我们在 7001 端口 redis 写入一条数据的时候,redis-cluster 会自动将该数据分配到对应的 redis 中的槽位里(即:7003 redis),且会自动切换到对应的 redis 下(即: 7003 redis)
OK
10.0.0.3:7003>


3.查询一条数据

[root@kevin_linux ~ 20:12:46]# redis-cli -c -p 7001
127.0.0.1:7001> get addr
-> Redirected to slot [12790] located at 10.0.0.3:7003  # 当我们在 7001 端口 redis 查询一条数据的时候,redis-cluster 会查询所有主redis下的槽位,然后返回对应的数据,并且自动切换到该槽位所对应的redis下(即: 7003 redis)
"hengli"
10.0.0.3:7003>